using System.Collections.Generic;
using UnityEngine;

public class SwordSkill : MonoBehaviour
{
    private static readonly int Rotate = Animator.StringToHash("rotate");
    private Player player;
    private Animator Anim => GetComponentInChildren<Animator>();
    private Rigidbody2D Rb => GetComponent<Rigidbody2D>();
    private CircleCollider2D CircleCollider2D => GetComponent<CircleCollider2D>();
    private ParticleSystem ps;
    private bool canRotate = true;
    private bool isReturning = false;
    private float freezeTimeDuration;
    private float returnSpeed;
    [Header("Bounce info")]
    private float bounceSpeed;
    private bool isBouncing;
    private int bounceCount;
    private List<Transform> enemyTargets;
    private int targetIndex;
    [Header("Pierce info")]
    private int pierceAmount;
    [Header("Spin info")]
    private float maxTravelDistance;
    private float spinDuration;
    private float spinTimer;
    private bool wasStopped;
    private bool isSpinning;
    private float hitTimer;
    private float hitCooldown;
    private float spinDirection;

    private void Awake()
    {
        ps = GetComponentInChildren<ParticleSystem>();
    }

    private void Start()
    {
        player = FindFirstObjectByType<Player>();
    }

    private void Update()
    {
        if (canRotate)
        {
            transform.right = Rb.velocity;
        }
        if (isReturning)
        {
            transform.position = Vector2.MoveTowards(transform.position, player.transform.position, returnSpeed * Time.deltaTime);
            if (Vector2.Distance(transform.position, player.transform.position) < 1f)
            {
                player.CatchTheSword();
            }
        }
        BounceLogic();
        SpinLogic();
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (!isReturning)
        {
            if (collision.TryGetComponent(out Enemy enemy))
            {
                SwordSkillDamage(enemy);
            }
            SetupTargetsForBounce(collision);
            StuctInto(collision);
        }
    }

    public void SetupSword(Vector2 direction, float gravityScale, Player player, float freezeTimeDuration, float returnSpeed)
    {
        this.freezeTimeDuration = freezeTimeDuration;
        this.returnSpeed = returnSpeed;
        Rb.velocity = direction;
        Rb.gravityScale = gravityScale;
        spinDirection = Mathf.Clamp(Rb.velocity.x, -1f, 1f);
        if (pierceAmount <= 0)
        {
            Anim.SetBool(Rotate, true);
        }
        Invoke(nameof(DestroyMe), 10f);
    }

    public void SetupBounce(bool isBouncing, int bounceCount, float bounceSpeed)
    {
        this.isBouncing = isBouncing;
        this.bounceCount = bounceCount;
        this.bounceSpeed = bounceSpeed;
        enemyTargets = new List<Transform>();
    }

    public void SetupPierce(int pierceAmount)
    {
        this.pierceAmount = pierceAmount;
    }

    public void SetupSpin(bool isSpinning, float maxTravelDistance, float spinDuration, float hitCooldown)
    {
        this.isSpinning = isSpinning;
        this.maxTravelDistance = maxTravelDistance;
        this.spinDuration = spinDuration;
        this.hitCooldown = hitCooldown;
    }

    private void BounceLogic()
    {
        if (!isBouncing || enemyTargets.Count <= 0) return;
        transform.position =
            Vector2.MoveTowards(transform.position, enemyTargets[targetIndex].position, bounceSpeed * Time.deltaTime);
        if (!(Vector2.Distance(transform.position, enemyTargets[targetIndex].position) <= 0.1f)) return;
        SwordSkillDamage(enemyTargets[targetIndex].GetComponent<Enemy>());
        targetIndex++;
        bounceCount--;
        if (bounceCount <= 0)
        {
            isBouncing = false;
            isReturning = true;
        }
        if (targetIndex >= enemyTargets.Count)
        {
            targetIndex = 0;
        }
    }

    private void SetupTargetsForBounce(Collider2D collision)
    {
        if (!isBouncing || enemyTargets.Count > 0 || !collision.TryGetComponent(out Enemy enemy)) return;
        Collider2D[] colliders = Physics2D.OverlapCircleAll(transform.position, 10f);
        foreach (var collider in colliders)
        {
            enemyTargets.Add(enemy.transform);
        }
    }

    private void SpinLogic()
    {
        if (isSpinning)
        {
            if (Vector2.Distance(player.transform.position, transform.position) > maxTravelDistance && !wasStopped)
            {
                StopWhenSpinning();
            }
            if (wasStopped)
            {
                spinTimer -= Time.deltaTime;
                // transform.position = Vector2.MoveTowards(transform.position, new Vector2(transform.position.x + spinDirection, transform.position.y), 1.5f * Time.deltaTime);
                if (spinTimer <= 0)
                {
                    isReturning = true;
                    wasStopped = false;
                }
                hitTimer -= Time.deltaTime;
                if (hitTimer > 0)
                {
                    return;
                }
                hitTimer = hitCooldown;
                Collider2D[] colliders = Physics2D.OverlapCircleAll(transform.position, 1f);
                foreach (var collider in colliders)
                {
                    if (collider.TryGetComponent(out Enemy enemy))
                    {
                        SwordSkillDamage(enemy);
                    }
                }
            }
        }
    }

    private void StopWhenSpinning()
    {
        wasStopped = true;
        Rb.constraints = RigidbodyConstraints2D.FreezePosition;
        spinTimer = spinDuration;
    }

    private void SwordSkillDamage(Enemy enemy)
    {
        player.Stats.DoDamage(enemy.Stats);
        if (player.SkillManager.Sword.TimeStopUnlocked)
            enemy.FreezeTimeFor(freezeTimeDuration);
        if (player.SkillManager.Sword.VulnerableUnlocked)
            enemy.Stats.MakeVulnerableFor(freezeTimeDuration);
        ItemDataEquipment equipedAmulet = player.Inventory.GetEquipment(EquipmentType.Amulet);
        if (equipedAmulet)
        {
            equipedAmulet.Effect(enemy.transform, player);
        }
    }

    private void StuctInto(Collider2D collision)
    {
        if (pierceAmount > 0 && collision.GetComponent<Enemy>() != null)
        {
            pierceAmount--;
            return;
        }
        if (isSpinning)
        {
            StopWhenSpinning();
            return;
        }
        canRotate = false;
        CircleCollider2D.enabled = false;
        Rb.isKinematic = true;
        Rb.constraints = RigidbodyConstraints2D.FreezeAll;
        ps.Play();
        if (isBouncing && enemyTargets.Count > 0) return;
        Anim.SetBool("rotate", false);
        transform.parent = collision.transform;
    }

    public void ReturnSword()
    {
        Rb.constraints = RigidbodyConstraints2D.FreezeAll;
        transform.parent = null;
        isReturning = true;
        // sword.skill.setcooldown;
    }

    private void DestroyMe()
    {
        Destroy(gameObject);
    }
}